# coding:utf-8
from django.db.models import Q, Sum, Subquery, OuterRef
from drf_yasg import openapi
#from drf_yasg.utils import swagger_auto_schema
from drf_yasg.utils import swagger_auto_schema
from rest_framework import status, views
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import generics
from drf_yasg.utils import swagger_auto_schema
from MSB_ERP.utils.base_serializer import ChoiceGoodsSerializer
from MSB_ERP.utils.cont import NumberPrefix
from MSB_ERP.utils.generate import generate_code
from MSB_ERP.utils.pagination import GlobalPagination
from goods_info.models import GoodsInventoryModel, GoodsModel
from erp_system.models import UserModel


class MultipleDestroyMixin:
    # 定义批量删除的视图类
    del_ids = openapi.Schema(type=openapi.TYPE_OBJECT, required=['ids'], properties={
        'ids': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_INTEGER),
                              description="选择需要删除的ID（主键）列表")
        # TYPE_ARRAY是列表，items列表里的元素是整数类型
    })  # TYPE_OBJECT传参是json格式,required参数名字,properties规定每个参数的具体类型

    # action装饰器可以接收两个参数：methods:该action对应的请求方式
    # detail:声明该action是否与单一资源对应，是否是xxx/<pk>/方法名
    # True表示路径是xxx/<pk>/方法名
    # False表示路径是xxx/方法名
    @swagger_auto_schema(method='delete', request_body=del_ids,
                         operation_description="批量删除")  # 在接口注释,request_body传参,适用于接口文档，在文档中添加multiple_delete
    @action(methods=['delete'], detail=False)
    def multiple_delete(self, request, *args, **kwargs):
        delete_ids = request.data.get('ids')
        if not delete_ids:
            return Response(data={'detail': '参数错误'}, status=status.HTTP_404_NOT_FOUND)

        if not isinstance(delete_ids, list):
            return Response(data={'detail': '类型错误'}, status=status.HTTP_404_NOT_FOUND)

        queryset = self.get_queryset()
        del_queryset = queryset.filter(id__in=delete_ids)
        if del_queryset.count() != len(delete_ids):
            return Response(data={'detail': '删除数据不存在'}, status=status.HTTP_400_BAD_REQUEST)

        del_queryset.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)




class MultipleOpenMixin:
    # 定义批量启用或者禁用的视图类
    del_ids = openapi.Schema(type=openapi.TYPE_OBJECT, required=['ids'], properties={
        'ids': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_INTEGER),
                              description="选择需要批量的ID（主键）列表"),
        'is_open': openapi.Schema(type=openapi.TYPE_STRING, description='是否启用，启用用：0，禁用：1')
        # TYPE_ARRAY是列表，items列表里的元素是整数类型
    })  # TYPE_OBJECT传参是json格式,required参数名字,properties规定每个参数的具体类型

    # action装饰器可以接收两个参数：methods:该action对应的请求方式
    # detail:声明该action是否与单一资源对应，是否是xxx/<pk>/方法名
    # True表示路径是xxx/<pk>/方法名
    # False表示路径是xxx/方法名
    @swagger_auto_schema(method='delete', request_body=del_ids,
                         operation_description="批量启用或禁用")  # 在接口注释,request_body传参,适用于接口文档，在文档中添加multiple_delete
    @action(methods=['delete'], detail=False)
    def multiple_open(self, request, *args, **kwargs):
        delete_ids = request.data.get('ids')
        delete_open = request.data.get('is_open', '0')
        if not delete_ids:
            return Response(data={'detail': '参数错误'}, status=status.HTTP_404_NOT_FOUND)

        if not isinstance(delete_ids, list):
            return Response(data={'detail': '类型错误'}, status=status.HTTP_404_NOT_FOUND)

        queryset = self.get_queryset()
        del_queryset = queryset.filter(id__in=delete_ids)
        if del_queryset.count() != len(delete_ids):
            return Response(data={'detail': '数据不存在'}, status=status.HTTP_400_BAD_REQUEST)

        del_queryset.update(delete_flag=delete_open)
        return Response(status=status.HTTP_200_OK)


# 生成各种编号的接口
class GenerateCode(views.APIView):
    prefix_param = openapi.Parameter(name='prefix', in_=openapi.IN_QUERY, description='编号的前缀',
                                     type=openapi.TYPE_STRING)

    @swagger_auto_schema(manual_parameters=[prefix_param],
                         operation_description="自动生成各种编号")
    def get(self, request, *args, **kwargs):
        """
            生成各种编号的接口，必须传一个前缀: /api/generate_code/prefix=ord，可以参考cont.py

            返回一个28位的编号字符串, return： code就是生成的编号
            """
        prefix = request.query_params.get('prefix', None)
        if prefix:
            if prefix in NumberPrefix.__members__:  # __members__成员，键
                code = generate_code(NumberPrefix[prefix].value)
                return Response(data={'code': code}, status=status.HTTP_200_OK)
            else:
                return Response(data={'detail': 'prefix没有配置'}, status=status.HTTP_400_BAD_REQUEST)
        else:
            return Response(data={'detail': 'prefix没有'}, status=status.HTTP_400_BAD_REQUEST)


class ChoiceGoodsSearchView(generics.GenericAPIView):
    serializer_class = ChoiceGoodsSerializer
    pagination_class = GlobalPagination

    # 分页参数必须是query_param(看源码)
    page_param = openapi.Parameter(name='page', in_=openapi.IN_QUERY, description="页号", type=openapi.TYPE_INTEGER)
    size_param = openapi.Parameter(name='size', in_=openapi.IN_QUERY, description="每页显示数量", type=openapi.TYPE_INTEGER)

    @swagger_auto_schema(operation_description='搜索需要选择的货品列表', request_body=ChoiceGoodsSerializer,
                         manual_parameters=[page_param, size_param])
    def post(self, request, *args, **kwargs):
        ser = ChoiceGoodsSerializer(data=request.data)
        if ser.is_valid():
            warehouse_id = ser.validated_data.get('warehouse_id', None)
            keyword = ser.validated_data.get('keyword', None)
            category_id = ser.validated_data.get('category_id', 0)
            number_code = ser.validated_data.get('number_code', None)
            query = Q()

            # 根据仓库来过滤查询，并且查询每个商品的库存,把商品库存查询结果作为子查询
            if warehouse_id:
                inventory_list = GoodsInventoryModel.objects.filter(warehouse_id=warehouse_id).filter(
                    goods_id=OuterRef('id')).values( #根据订单ID,引用外部查询的值
                    'goods_id').annotate(total_sum=Sum('cur_inventory'))
            else:  # 没有指定仓库,意味着查询每个商品总库存和，基于goods_id进行链表查询
                inventory_list = GoodsInventoryModel.objects.filter(goods_id=OuterRef('id')).values(
                    'goods_id').annotate(total_sum=Sum('cur_inventory'))  # annotate分组

            # 基于GoodsModel的过滤查询
            if keyword:
                child_query = Q()
                child_query.add(Q(name__contains=keyword), 'OR')
                child_query.add(Q(specification=keyword), 'OR')
                child_query.add(Q(model_number=keyword), 'OR')
                query.add(child_query, 'AND')
            if category_id:
                query.add(Q(category__id=category_id), 'AND')
            if number_code:
                query.add(Q(number_code__contains=number_code), 'AND')
            #根据查询结果，给子查询进行连表查询
            result = GoodsModel.objects.filter(query).values('id', 'name', 'number_code', 'specification',
                                                             'model_number', 'color', 'units__basic_name',
                                                             'category__name', 'category_id').annotate(
                cur_inventory=Subquery(inventory_list.values('total_sum'))).all()
            pg_result = self.paginate_queryset(result)  # 加上分页
            # pgresult就是查询结果，借助序列化帮忙序列化
            result_ser = self.get_serializer(instance=pg_result, many=True)
        return self.get_paginated_response(result_ser.data)




class MultipleAuditMixin:
    # 定义批量审核的视图类
    body_json = openapi.Schema(type=openapi.TYPE_OBJECT, required=['ids'], properties={
        'ids': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_INTEGER),
                              description="选择需要审核的ID（主键）列表"),
        'user_id': openapi.Schema(type=openapi.TYPE_INTEGER, description='审核用户的ID'),
        'is_audit': openapi.Schema(type=openapi.TYPE_STRING, description='是否审核，审核：1，反审核：0'),
        # TYPE_ARRAY是列表，items列表里的元素是整数类型
    })  # TYPE_OBJECT传参是json格式,required参数名字,properties规定每个参数的具体类型

    # action装饰器可以接收两个参数：methods:该action对应的请求方式
    # detail:声明该action是否与单一资源对应，是否是xxx/<pk>/方法名
    # True表示路径是xxx/<pk>/方法名
    # False表示路径是xxx/方法名
    @swagger_auto_schema(method='put', request_body=body_json,
                         operation_description="批量审核")  # 在接口注释,request_body传参,适用于接口文档，在文档中添加multiple_delete
    @action(methods=['put'], detail=False)
    def multiple_audit(self, request, *args, **kwargs):
        audit_ids = request.data.get('ids')
        user_id = request.data.get('user_id')#用户id
        is_audit = request.data.get('is_audit')#反审核
        if not audit_ids:
            return Response(data={'detail': '参数错误'}, status=status.HTTP_404_NOT_FOUND)

        if not isinstance(audit_ids, list):
            return Response(data={'detail': '类型错误'}, status=status.HTTP_404_NOT_FOUND)

        queryset = self.get_queryset()
        del_queryset = queryset.filter(id__in=audit_ids)
        if del_queryset.count() != len(audit_ids):
            return Response(data={'detail': '审核数据不存在'}, status=status.HTTP_400_BAD_REQUEST)

        for item in del_queryset.all():#item代表一个订单
            if item.status != '1' and is_audit == '0': #订单状态为1以后的是不可以反审核
                return Response(data={'detail': '不能反审核'}, status=status.HTTP_404_NOT_FOUND)
            if item.status != '0' and is_audit == '1': #订单状态不是0是不可以审核的
                return Response(data={'detail': '不能审核'}, status=status.HTTP_404_NOT_FOUND)

        #用户iD
        if not user_id:
            return Response(data={'detail': '参数错误'}, status=status.HTTP_404_NOT_FOUND)
        check_user=UserModel.objects.get(id=int(user_id))

        del_queryset.update(status=is_audit,check_user_name=check_user.real_name,check_user_id=check_user.id)


        return Response(status=status.HTTP_200_OK)































